package com.tools.middle.redis.client;

import com.fasterxml.jackson.core.type.TypeReference;
import com.tools.common.object.C;
import com.tools.common.object.json.JsonKit;
import com.tools.common.object.Note;
import com.tools.common.object.ObjKit;
import redis.clients.jedis.ListPosition;

import java.util.ArrayList;
import java.util.List;

/**
 * Redis List 类型
 * 的操作方法抽象实现
 * */
@Note("Redis List 类型的操作方法抽象实现")
abstract class TypeList extends TypeHash {

    TypeList() {}

    /* **********************************************************************************
     *
     *          同名 - 需要手动 close 的操作方法
     *
     * *********************************************************************************
     * */

    public long lpush(String key, Object value) {
        DataTypeKit.default_checkKey(key);
        Long result = this.jedis().lpush(key, ObjKit.toStringEmptyString(value));
        return DataTypeKit.default_returnResultLong(result);
    }

    public long lpush(String key, Object... values) {
        DataTypeKit.default_checkKey(key);
        Long result = this.jedis().lpush(key, DataTypeKit.default_asStringArray(values));
        return DataTypeKit.default_returnResultLong(result);
    }

    public long lpush(String key, Iterable values) {
        DataTypeKit.default_checkKey(key);
        Long result = this.jedis().lpush(key, DataTypeKit.default_asStringArray(values));
        return DataTypeKit.default_returnResultLong(result);
    }
    
    public List<Object> lrange(String key, long start, long stop) {
        DataTypeKit.default_checkKey(key);
        List<String> res = this.jedis().lrange(key, start, stop);
        return DataTypeKit.default_asObjectList(res);
    }


    public <T> List<T> lrange(String key, long start, long stop, Class<T> valueType) {
        DataTypeKit.default_checkKey(key);
        List<String> res = this.jedis().lrange(key, start, stop);
        return DataTypeKit.default_asSpecifyTypeList(res, valueType);
    }


    public <T> List<T> lrange(String key, long start, long stop, TypeReference<T> valueType) {
        DataTypeKit.default_checkKey(key);
        List<String> res = this.jedis().lrange(key, start, stop);
        return DataTypeKit.default_asSpecifyTypeList(res, valueType);
    }


    public <T> List<T> lrange(String key, long start, long stop, C<T> valueType) {
        DataTypeKit.default_checkKey(key);
        List<String> res = this.jedis().lrange(key, start, stop);
        List<T> result = new ArrayList<>(res.size());
        for (String s : res) {
            result.add(JsonKit.toEntity(s, valueType));
        }
        return result;
    }

    public Object lpop(String key) {
        DataTypeKit.default_checkKey(key);
        String res = this.jedis().lpop(key);
        return ObjKit.stringToRealValue(res, true);
    }

    public <T> T lpop(String key, Class<T> valueType) {
        DataTypeKit.default_checkKey(key);
        String res = this.jedis().lpop(key);
        return JsonKit.toEntity(res, valueType);
    }

    public <T> T lpop(String key, TypeReference<T> valueType) {
        DataTypeKit.default_checkKey(key);
        String res = this.jedis().lpop(key);
        return JsonKit.toEntity(res, valueType);
    }

    public <T> T lpop(String key, C<T> valueType) {
        DataTypeKit.default_checkKey(key);
        String res = this.jedis().lpop(key);
        return JsonKit.toEntity(res, valueType);
    }

    public List<Object> lpop(String key, int count) {
        DataTypeKit.default_checkKey(key);
        List<String> res = this.jedis().lpop(key, count);
        return DataTypeKit.default_asObjectList(res);
    }

    public <T> List<T> lpop(String key, int count, Class<T> valueType) {
        DataTypeKit.default_checkKey(key);
        List<String> res = this.jedis().lpop(key, count);
        return DataTypeKit.default_asSpecifyTypeList(res, valueType);
    }

    public <T> List<T> lpop(String key, int count, TypeReference<T> valueType) {
        DataTypeKit.default_checkKey(key);
        List<String> res = this.jedis().lpop(key, count);
        return DataTypeKit.default_asSpecifyTypeList(res, valueType);
    }

    public <T> List<T> lpop(String key, int count, C<T> valueType) {
        DataTypeKit.default_checkKey(key);
        List<String> res = this.jedis().lpop(key, count);
        return DataTypeKit.default_asSpecifyTypeList(res, valueType);
    }

    @Note("返回列表中指定索引的值")
    public Object lindex(String key, long index) {
        DataTypeKit.default_checkKey(key);
        String res = this.jedis().lindex(key, index);
        return ObjKit.stringToRealValue(res, true);
    }

    public <T> T lindex(String key, long index, Class<T> valueType) {
        DataTypeKit.default_checkKey(key);
        String res = this.jedis().lindex(key, index);
        return JsonKit.toEntity(res, valueType);
    }

    public <T> T lindex(String key, long index, TypeReference<T> valueType) {
        DataTypeKit.default_checkKey(key);
        String res = this.jedis().lindex(key, index);
        return JsonKit.toEntity(res, valueType);
    }

    public <T> T lindex(String key, long index, C<T> valueType) {
        DataTypeKit.default_checkKey(key);
        String res = this.jedis().lindex(key, index);
        return (T) ObjKit.stringToRealValue(res, valueType);
    }

    @Note("列表存在时，从头部插入元素")
    public long lpushx(String key, Object value) {
        DataTypeKit.default_checkKey(key);
        Long result = this.jedis().lpushx(key, ObjKit.toStringEmptyString(value));
        return DataTypeKit.default_returnResultLong(result);
    }

    @Note("列表存在时，从头部插入所有元素")
    public long lpushx(String key, Object... newValues) {
        DataTypeKit.default_checkKey(key);
        Long result = this.jedis().lpushx(key, DataTypeKit.default_asStringArray(newValues));
        return DataTypeKit.default_returnResultLong(result);
    }

    public long lpushx(String key, Iterable newValues) {
        DataTypeKit.default_checkKey(key);
        Long result = this.jedis().lpushx(key, DataTypeKit.default_asStringArray(newValues));
        return DataTypeKit.default_returnResultLong(result);
    }

    public String lset(String key, long index, Object value) {
        DataTypeKit.default_checkKey(key);
        return this.jedis().lset(key, index, ObjKit.toStringEmptyString(value));
    }

    @Note("返回列表的长度")
    public long llen(String key) {
        DataTypeKit.default_checkKey(key);
        Long length = this.jedis().llen(key);
        return DataTypeKit.default_returnResultLong(length);
    }

    @Note("让列表保留指定区间的内容，其余的全部删除")
    public String ltrim(String key, long start, long stop) {
        DataTypeKit.default_checkKey(key);
        return this.jedis().ltrim(key, start, stop);
    }

    @Note("将 value 插入到 pivot 之前还是之后的位置")
    public long linsert(String key, ListPosition position, Object pivot, Object value) {
        DataTypeKit.default_checkKey(key);
        Long result = this.jedis().linsert(key, position,
                ObjKit.toStringEmptyString(pivot),
                ObjKit.toStringEmptyString(value));
        return DataTypeKit.default_returnResultLong(result);
    }

    @Note("删除列表与 removeValue 相同的 value，count 为删除个数，为 0 则移除全部与之相同的 value")
    public long lrem(String key, Object removeValue, long count) {
        DataTypeKit.default_checkKey(key);
        Long result = this.jedis().lrem(key, count, ObjKit.toStringEmptyString(removeValue));
        return DataTypeKit.default_returnResultLong(result);
    }


    public long rpush(String key, Object value) {
        DataTypeKit.default_checkKey(key);
        Long result = this.jedis().rpush(key, ObjKit.toStringEmptyString(value));
        return DataTypeKit.default_returnResultLong(result);
    }

    public long rpush(String key, Object... values) {
        DataTypeKit.default_checkKey(key);
        Long result = this.jedis().rpush(key, DataTypeKit.default_asStringArray(values));
        return DataTypeKit.default_returnResultLong(result);
    }


    public long rpush(String key, Iterable values) {
        DataTypeKit.default_checkKey(key);
        Long result = this.jedis().rpush(key, DataTypeKit.default_asStringArray(values));
        return DataTypeKit.default_returnResultLong(result);
    }


    public Object rpop(String key) {
        DataTypeKit.default_checkKey(key);
        String res = this.jedis().rpop(key);
        return ObjKit.stringToRealValue(res, true);
    }

    public <T> T rpop(String key, Class<T> valueType) {
        DataTypeKit.default_checkKey(key);
        String res = this.jedis().rpop(key);
        return JsonKit.toEntity(res, valueType);
    }

    public <T> T rpop(String key, TypeReference<T> valueType) {
        DataTypeKit.default_checkKey(key);
        String res = this.jedis().rpop(key);
        return JsonKit.toEntity(res, valueType);
    }

    public <T> T rpop(String key, C<T> valueType) {
        DataTypeKit.default_checkKey(key);
        String res = this.jedis().rpop(key);
        return (T) ObjKit.stringToRealValue(res, valueType);
    }

    public List<Object> rpop(String key, int count) {
        DataTypeKit.default_checkKey(key);
        List<String> res = this.jedis().rpop(key, count);
        return DataTypeKit.default_asObjectList(res);
    }

    public <T> List<T> rpop(String key, int count, Class<T> valueType) {
        DataTypeKit.default_checkKey(key);
        List<String> res = this.jedis().rpop(key, count);
        return DataTypeKit.default_asSpecifyTypeList(res, valueType);
    }

    public <T> List<T> rpop(String key, int count, TypeReference<T> valueType) {
        DataTypeKit.default_checkKey(key);
        List<String> res = this.jedis().rpop(key, count);
        return DataTypeKit.default_asSpecifyTypeList(res, valueType);
    }

    public <T> List<T> rpop(String key, int count, C<T> valueType) {
        DataTypeKit.default_checkKey(key);
        List<String> res = this.jedis().rpop(key, count);
        return DataTypeKit.default_asSpecifyTypeList(res, valueType);
    }


    public long rpushx(String key, Object value) {
        DataTypeKit.default_checkKey(key);
        Long result = this.jedis().rpushx(key, ObjKit.toStringEmptyString(value));
        return DataTypeKit.default_returnResultLong(result);
    }

    public long rpushx(String key, Object... values) {
        DataTypeKit.default_checkKey(key);
        Long result = this.jedis().rpushx(key, DataTypeKit.default_asStringArray(values));
        return DataTypeKit.default_returnResultLong(result);
    }

    public long rpushx(String key, Iterable values) {
        DataTypeKit.default_checkKey(key);
        Long result = this.jedis().rpushx(key, DataTypeKit.default_asStringArray(values));
        return DataTypeKit.default_returnResultLong(result);
    }


    /* **********************************************************************************
     *
     *          带【$】 - 自动 close 的操作方法
     *
     * *********************************************************************************
     * */

    public long lpush$(String key, Object value) {
        try {
            return this.lpush(key, value);
        } finally {
            this.close();
        }
    }

    public long lpush$(String key, Object... values) {
        try {
            return this.lpush(key, values);
        } finally {
            this.close();
        }
    }

    public long lpush$(String key, Iterable values) {
        try {
            return this.lpush(key, values);
        } finally {
            this.close();
        }
    }


    public List<Object> lrange$(String key, long start, long stop) {
        try {
            return this.lrange(key, start, stop);
        } finally {
            this.close();
        }
    }


    public <T> List<T> lrange$(String key, long start, long stop, Class<T> valueType) {
        try {
            return this.lrange(key, start, stop, valueType);
        } finally {
            this.close();
        }
    }


    public <T> List<T> lrange$(String key, long start, long stop, TypeReference<T> valueType) {
        try {
            return this.lrange(key, start, stop, valueType);
        } finally {
            this.close();
        }
    }


    public <T> List<T> lrange$(String key, long start, long stop, C<T> valueType) {
        try {
            return this.lrange(key, start, stop, valueType);
        } finally {
            this.close();
        }
    }

    public Object lpop$(String key) {
        try {
            return this.lpop(key);
        } finally {
            this.close();
        }
    }

    public <T> T lpop$(String key, Class<T> valueType) {
        try {
            return this.lpop(key, valueType);
        } finally {
            this.close();
        }
    }

    public <T> T lpop$(String key, TypeReference<T> valueType) {
        try {
            return this.lpop(key, valueType);
        } finally {
            this.close();
        }
    }

    public <T> T lpop$(String key, C<T> valueType) {
        try {
            return this.lpop(key, valueType);
        } finally {
            this.close();
        }
    }

    public List<Object> lpop$(String key, int count) {
        try {
            return this.lpop(key, count);
        } finally {
            this.close();
        }
    }

    public <T> List<T> lpop$(String key, int count, Class<T> valueType) {
        try {
            return this.lpop(key, count, valueType);
        } finally {
            this.close();
        }
    }

    public <T> List<T> lpop$(String key, int count, TypeReference<T> valueType) {
        try {
            return this.lpop(key, count, valueType);
        } finally {
            this.close();
        }
    }

    public <T> List<T> lpop$(String key, int count, C<T> valueType) {
        try {
            return this.lpop(key, count, valueType);
        } finally {
            this.close();
        }
    }

    @Note("返回列表中指定索引的值")
    public Object lindex$(String key, long index) {
        try {
            return this.lindex(key, index);
        } finally {
            this.close();
        }
    }

    public <T> T lindex$(String key, long index, Class<T> valueType) {
        try {
            return this.lindex(key, index, valueType);
        } finally {
            this.close();
        }
    }

    public <T> T lindex$(String key, long index, TypeReference<T> valueType) {
        try {
            return this.lindex(key, index, valueType);
        } finally {
            this.close();
        }
    }

    public <T> T lindex$(String key, long index, C<T> valueType) {
        try {
            return this.lindex(key, index, valueType);
        } finally {
            this.close();
        }
    }


    @Note("列表存在时，从头部插入元素")
    public long lpushx$(String key, Object value) {
        try {
            return this.lpushx(key, value);
        } finally {
            this.close();
        }
    }

    @Note("列表存在时，从头部插入所有元素")
    public long lpushx$(String key, Object... newValues) {
        try {
            return this.lpushx(key, newValues);
        } finally {
            this.close();
        }
    }

    public long lpushx$(String key, Iterable newValues) {
        try {
            return this.lpushx(key, newValues);
        } finally {
            this.close();
        }
    }


    public String lset$(String key, long index, Object value) {
        try {
            return this.lset(key, index, value);
        } finally {
            this.close();
        }
    }

    @Note("返回列表的长度")
    public long llen$(String key) {
        try {
            return this.llen(key);
        } finally {
            this.close();
        }
    }

    @Note("让列表保留指定区间的内容，其余的全部删除")
    public String ltrim$(String key, long start, long stop) {
        try {
            return this.ltrim(key, start, stop);
        } finally {
            this.close();
        }
    }

    @Note("将 value 插入到 pivot 之前还是之后的位置")
    public long linsert$(String key, ListPosition position, Object pivot, Object value) {
        try {
            return this.linsert(key, position, pivot, value);
        } finally {
            this.close();
        }
    }

    @Note("删除列表与 removeValue 相同的 value，count 为删除个数，为 0 则移除全部与之相同的 value")
    public long lrem$(String key, Object removeValue, long count) {
        try {
            return this.lrem(key, removeValue, count);
        } finally {
            this.close();
        }
    }


    public long rpush$(String key, Object value) {
        try {
            return this.rpush(key, value);
        } finally {
            this.close();
        }
    }

    public long rpush$(String key, Object... values) {
        try {
            return this.rpush(key, values);
        } finally {
            this.close();
        }
    }


    public long rpush$(String key, Iterable values) {
        try {
            return this.rpush(key, values);
        } finally {
            this.close();
        }
    }

    public Object rpop$(String key) {
        try {
            return this.rpop(key);
        } finally {
            this.close();
        }
    }

    public <T> T rpop$(String key, Class<T> valueType) {
        try {
            return this.rpop(key, valueType);
        } finally {
            this.close();
        }
    }

    public <T> T rpop$(String key, TypeReference<T> valueType) {
        try {
            return this.rpop(key, valueType);
        } finally {
            this.close();
        }
    }

    public <T> T rpop$(String key, C<T> valueType) {
        try {
            return this.rpop(key, valueType);
        } finally {
            this.close();
        }
    }


    public List<Object> rpop$(String key, int count) {
        try {
            return this.rpop(key, count);
        } finally {
            this.close();
        }
    }


    public <T> List<T> rpop$(String key, int count, Class<T> valueType) {
        try {
            return this.rpop(key, count, valueType);
        } finally {
            this.close();
        }
    }

    public <T> List<T> rpop$(String key, int count, TypeReference<T> valueType) {
        try {
            return this.rpop(key, count, valueType);
        } finally {
            this.close();
        }
    }

    public <T> List<T> rpop$(String key, int count, C<T> valueType) {
        try {
            return this.rpop(key, count, valueType);
        } finally {
            this.close();
        }
    }


    public long rpushx$(String key, Object value) {
        try {
            return this.rpushx(key, value);
        } finally {
            this.close();
        }
    }

    public long rpushx$(String key, Object... values) {
        try {
            return this.rpushx(key, values);
        } finally {
            this.close();
        }
    }

    public long rpushx$(String key, Iterable values) {
        try {
            return this.rpushx(key, values);
        } finally {
            this.close();
        }
    }

}
